#include "Bridge.h"
#include <Windows.h>
#include <tchar.h>

Bridge::Bridge()
{
	this->pProtocol = new Protocol(10, 10);
	this->pIF = NULL;

	ComParams *comParams = new ComParams();
	comParams->SetBaudRate("115200");
	comParams->SetStopBits("1");
	comParams->SetParity("None");
	comParams->SetByteSize("8");
	comParams->SetIgnoreDSR(true);

	this->pComParams = comParams;
}


Bridge::~Bridge()
{
}


SOCKET Bridge::CreateSocket()
{
	int type = SOCK_STREAM;
	int proto = IPPROTO_TCP;

	if (mode == WorkMode::UDP) {
		type = SOCK_DGRAM;
		proto = IPPROTO_UDP;
	}

	SOCKET hSock = socket(AF_INET, type, proto);
	if (hSock == INVALID_SOCKET) {
		//TraceLastError("Socket(): socket()");
		return INVALID_SOCKET;
	}

	if (this->pIF || this->pPort) {
		struct sockaddr_in sn;
		if (!SetAddr(sn, this->pIF, this->pPort))
			return INVALID_SOCKET;

		if (bind(hSock, (struct sockaddr *)&sn, sizeof(sn)) == SOCKET_ERROR) {
			//TraceLastError("Socket(): bind(\"%s\", \"%s\")", pIF, pPort);
			closesocket(hSock);
			return INVALID_SOCKET;
		}
	}

	return hSock;
}

BOOL Bridge::SetAddr(struct sockaddr_in &sn, const char *ipAddr, const char *port)
{
	memset(&sn, 0, sizeof(sn));
	sn.sin_family = AF_INET;
	sn.sin_port = port ? htons((u_short)atoi(port)) : 0;
	sn.sin_addr.s_addr = ipAddr ? inet_addr(ipAddr) : INADDR_ANY;

	if (sn.sin_addr.s_addr == INADDR_NONE) {
		const struct hostent *pHostEnt = gethostbyname(ipAddr);
		if (!pHostEnt)
			return FALSE;

		memcpy(&sn.sin_addr, pHostEnt->h_addr, pHostEnt->h_length);
	}
	return TRUE;
}

Bridge *Bridge::LoadFromRegistry(const char *comName)
{
#define BUF_SIZE 512

	HKEY hKey;
	char sKeyName[BUF_SIZE];
	BYTE sKeyValue[BUF_SIZE];
	DWORD dwBufSize, dwType;
	DWORD dwRes;

	// Set NT service parameters
	sprintf(sKeyName, "SYSTEM\\CurrentControlSet\\Services\\tcp2com-0\\%s", comName);
	dwRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sKeyName, 0, KEY_ALL_ACCESS, &hKey);
	if (dwRes != ERROR_SUCCESS)
		return NULL;

	Bridge *pBridge = new Bridge();
	dwBufSize = BUF_SIZE;
	dwRes = RegQueryValueEx(hKey, "Mode", NULL, &dwType, sKeyValue, &dwBufSize);
	pBridge->mode = (WorkMode)*(DWORD *)sKeyValue;

	dwBufSize = BUF_SIZE;
	dwRes = RegQueryValueEx(hKey, "ComPath", NULL, &dwType, sKeyValue, &dwBufSize);
	pBridge->comPath = _strdup((char *)sKeyValue);

	dwBufSize = BUF_SIZE;
	dwRes = RegQueryValueEx(hKey, "IPAddr", NULL, &dwType, sKeyValue, &dwBufSize);
	pBridge->pIP = _strdup((char *)sKeyValue);

	dwBufSize = BUF_SIZE;
	dwRes = RegQueryValueEx(hKey, "Port", NULL, &dwType, sKeyValue, &dwBufSize);
	pBridge->pPort = _strdup((char *)sKeyValue);

	dwBufSize = BUF_SIZE;
	dwRes = RegQueryValueEx(hKey, "LocalPort", NULL, &dwType, sKeyValue, &dwBufSize);
	pBridge->pLocalPort = _strdup((char *)sKeyValue);

	RegCloseKey(hKey);

	return pBridge;
}


BOOL Bridge::SaveToRegistry()
{
	HKEY hKey;
	char sKeyName[512] = {0};
	DWORD dwDisposition;
	DWORD iFreeKey = 0;

	strcpy(sKeyName, "SYSTEM\\CurrentControlSet\\Services\\tcp2com-0");
	DWORD lRes = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
		sKeyName,
		0,
		"",
		REG_OPTION_NON_VOLATILE,
		KEY_ALL_ACCESS,
		NULL,
		&hKey,
		&dwDisposition);

	const char * displayName = "TCP - COM bridge";
	lRes = RegSetValueEx(hKey, "DisplayName", 0, REG_SZ, (const BYTE *)displayName, (DWORD)strlen(displayName) + 1);
	RegCloseKey(hKey);

	// Set NT service parameters
	sprintf(sKeyName, "SYSTEM\\CurrentControlSet\\Services\\tcp2com-%i\\%s", iFreeKey, this->comPath + 4);
	lRes = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
		sKeyName,
		0,
		"",
		REG_OPTION_NON_VOLATILE,
		KEY_ALL_ACCESS,
		NULL,
		&hKey,
		&dwDisposition);

	RegSetValueEx(hKey, "Mode", 0, REG_DWORD, (BYTE *)&this->mode, sizeof(WorkMode));
	RegSetValueEx(hKey, "ComPath", 0, REG_SZ, (BYTE *)this->comPath, (DWORD)strlen(this->comPath));
	RegSetValueEx(hKey, "IPAddr", 0, REG_SZ, (BYTE *)this->pIP, (DWORD)strlen(this->pIP));
	RegSetValueEx(hKey, "Port", 0, REG_SZ, (BYTE *)this->pPort, (DWORD)strlen(pPort));
	RegSetValueEx(hKey, "LocalPort", 0, REG_SZ, (BYTE *)this->pLocalPort, sizeof(this->pLocalPort));

	RegCloseKey(hKey);

	return TRUE;
}


list<Bridge *> Bridge::LoadFromDB()
{
#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383

	list<Bridge *> bridgeList = list<Bridge *>();

	DWORD    cSubKeys = 0;               // number of subkeys 
	DWORD    cValues;              // number of values for key 
	DWORD i;
	HKEY hKey;

	const char *keyPath = "SYSTEM\\CurrentControlSet\\Services\\tcp2com-0";
	DWORD dwRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS, &hKey);
	if (dwRes != ERROR_SUCCESS)
		return bridgeList;

	// Get the class name and the value count. 
	dwRes = RegQueryInfoKey(
		hKey,                    // key handle 
		NULL,                    // buffer for class name 
		NULL,                    // size of class string 
		NULL,                    // reserved 
		&cSubKeys,               // number of subkeys 
		NULL,                    // longest subkey size 
		NULL,                    // longest class string 
		&cValues,                // number of values for this key 
		NULL,                    // longest value name 
		NULL,                    // longest value data 
		NULL,                    // security descriptor 
		NULL);                   // last write time 

	// Enumerate the subkeys, until RegEnumKeyEx fails.
	for (i = 0; i<cSubKeys; i++) {
		TCHAR achKey[MAX_KEY_LENGTH];   // buffer for subkey name
		DWORD cbName = MAX_KEY_LENGTH;

		dwRes = RegEnumKeyEx(hKey, i,
			achKey,
			&cbName,
			NULL,
			NULL,
			NULL,
			NULL);
		if (dwRes == ERROR_SUCCESS) {
			Bridge *pBridge = LoadFromRegistry(achKey);
			if (pBridge) {
				bridgeList.push_back(pBridge);
			}
		}
	}

	return bridgeList;
}
